package com.inkyi.assistant.app.component.rsyntax;

import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.formdev.flatlaf.icons.FlatSearchWithHistoryIcon;
import com.inkyi.assistant.app.base.BaseFrame;
import com.inkyi.assistant.app.utils.MigLayoutHelper;
import com.inkyi.framework.common.utils.EmptyHelper;
import com.inkyi.framework.daqian.share.component.ArrowFoldButton;
import com.inkyi.framework.daqian.share.utils.SwingUtils;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.SearchContext;
import org.fife.ui.rtextarea.SearchEngine;
import org.fife.ui.rtextarea.SearchResult;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;

/**
 * 查询、替换面板
 */
public class RSyntaxTextFindBar extends JPanel {
    /**
     * 下一个、上一个的位置
     */
    private int findNextPrevIdx = 1;
    /**
     * 显示替换相关的面板，true/false
     */
    private final String showReplaceCompKey = "showReplaceComp";
    /**
     * 折叠按钮
     */
    private ArrowFoldButton foldButton;
    /**
     * 查找相关组件
     */
    private JTextField findField;
    private JToggleButton matchCaseButton;
    private JToggleButton wordsButton;
    private JToggleButton regexButton;
    private JButton findPrevButton;
    private JButton findNextButton;
    private JButton closeButton;
    private JLabel findLabel;
    /**
     * 替换相关组件
     */
    private JTextField replaceField;
    private JButton replaceButton;
    private JButton replaceAllButton;
    /**
     * 文本域相关组件
     */
    private final RSyntaxTextArea textArea;
    private final SearchContext searchContext;

    public RSyntaxTextFindBar(boolean showReplace, RSyntaxTextArea textArea, SearchContext searchContext) {
        SwingUtils.putClientProperty(this, showReplaceCompKey, showReplace);
        this.textArea = textArea;
        this.searchContext = searchContext;
        this.searchContext.setSearchWrap(true);
        setupUI();
        initConfig();
    }


    public void setupUI() {
        setLayout(MigLayoutHelper.create("hidemode 3", "[][][][]", "[][]"));
        Boolean showReplace = (Boolean) SwingUtils.getClientProperty(this, showReplaceCompKey);

        foldButton = new ArrowFoldButton();
        foldButton.setArroDown(showReplace);

        findField = createFindField();
        replaceField = createReplaceField();

        findPrevButton = new JButton(new FlatSVGIcon("icons/directionUp.svg"));
        findPrevButton.setPressedIcon(new FlatSVGIcon("icons/directionUpPressed.svg"));
        findPrevButton.setToolTipText("上一个");

        findNextButton = new JButton(new FlatSVGIcon("icons/directionDown.svg"));
        findNextButton.setPressedIcon(new FlatSVGIcon("icons/directionDownPressed.svg"));
        findNextButton.setToolTipText("下一个");

        findLabel = new JLabel("0个结果");

        closeButton = new JButton(new FlatSVGIcon("icons/close.svg"));
        closeButton.setPressedIcon(new FlatSVGIcon("icons/closePressed.svg"));
        closeButton.setToolTipText("关闭");

        replaceButton = new JButton("替换");
        replaceAllButton = new JButton("替换全部");

        // 第1行-第1列,占前两行的第一列
        add(foldButton, MigLayoutHelper.constraints().cell(0, 0, 1, 2).align().top().build());
        // 第2列
        add(findField, MigLayoutHelper.constraints().cell(1, 0).width(300).build());
        // 第3列
        add(findLabel, MigLayoutHelper.constraints().cell(1, 0).build());
        add(findPrevButton, MigLayoutHelper.constraints().cell(2, 0).build());
        add(findNextButton, MigLayoutHelper.constraints().cell(2, 0).build());
        add(findNextButton, MigLayoutHelper.constraints().cell(2, 0).build());
        // 第4列
        add(closeButton, MigLayoutHelper.constraints().cell(3, 0).push("x").align().right().build());
        // 第2行
        add(replaceField, MigLayoutHelper.constraints().cell(1, 1).width(300).build());
        add(replaceButton, MigLayoutHelper.constraints().cell(2, 1).build());
        add(replaceAllButton, MigLayoutHelper.constraints().cell(2, 1).build());

        updateReplaceComp(showReplace);

    }

    public void initConfig() {
        findField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                find();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                find();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
            }
        });

        matchCaseButton.addActionListener(e -> markAll());
        regexButton.addActionListener(e -> markAll());
        wordsButton.addActionListener(e -> markAll());
        findPrevButton.addActionListener(e -> findPrevious());
        findNextButton.addActionListener(e -> findNext());
        replaceButton.addActionListener(e -> replace());
        replaceAllButton.addActionListener(e -> replaceAll());
        foldButton.addActionListener(e -> {
            ArrowFoldButton source = (ArrowFoldButton) e.getSource();
            updateReplaceComp(source.isArrowDown());
        });
        closeButton.addActionListener(e -> close());
    }


    private void findNext() {
        searchContext.setSearchForward(true);
        SearchResult searchResult = doFindOrMarkAll(true);
        updateFindLable(searchResult);
    }

    private void findPrevious() {
        searchContext.setSearchForward(false);
        SearchResult searchResult = doFindOrMarkAll(true);
        updateFindLable(searchResult);
    }

    private void find() {
        SearchResult searchResult = doFindOrMarkAll(true);
        findNextPrevIdx = 0;
        updateFindLable(searchResult);

    }

    private void markAll() {
        SearchResult searchResult = doFindOrMarkAll(false);
        findNextPrevIdx = 0;
        updateFindLable(searchResult);
    }

    private void replace() {
        SearchResult searchResult = doReplace(false);
        findNextPrevIdx = 0;
        updateFindLable(searchResult);
    }

    private void replaceAll() {
        SearchResult searchResult = doReplace(true);
        findNextPrevIdx = 0;
        updateFindLable(searchResult);
    }

    private void close() {
        this.setVisible(false);
        searchContext.setSearchFor(null);
        SearchEngine.markAll(textArea, searchContext);
    }

    /**
     * 查找或标记全部
     *
     * @param find 找到
     * @return {@link SearchResult }
     */
    private SearchResult doFindOrMarkAll(boolean find) {
        String findText = findField.getText();
        if (EmptyHelper.isNotEmpty(findText)) {
            searchContext.setSearchFor(findText);
            searchContext.setMatchCase(matchCaseButton.isSelected()); //是否区分大小写
            searchContext.setRegularExpression(regexButton.isSelected()); //是否允许正则表达式
            searchContext.setWholeWord(wordsButton.isSelected());
            SearchResult searchResult = find ? SearchEngine.find(textArea, searchContext) : SearchEngine.markAll(textArea, searchContext);
            return searchResult;
        }
        return null;
    }

    /**
     * 替换
     *
     * @param all 所有
     * @return {@link SearchResult }
     */
    private SearchResult doReplace(boolean all) {
        String findText = findField.getText();
        String replaceText = replaceField.getText();
        if (EmptyHelper.isNotEmpty(findText)) {
            searchContext.setSearchFor(findText);
            searchContext.setReplaceWith(replaceText);
            //确保禁用搜索换行，否则很容易在替换时进行无限循环。"a"配"aa"
            boolean oldSearchWrap = searchContext.getSearchWrap();
            searchContext.setSearchWrap(false);
            SearchResult searchResult = all ? SearchEngine.replaceAll(textArea, searchContext) : SearchEngine.replace(textArea, searchContext);
            // 恢复搜索行
            searchContext.setSearchWrap(oldSearchWrap);
            return searchResult;
        }
        return null;
    }

    /**
     * 更新查找标签 0/0
     *
     * @param searchResult 搜索结果
     */
    private void updateFindLable(SearchResult searchResult) {
        System.out.println(searchResult);
        if (searchResult == null) {
            findLabel.setText("0个结果");
            return;
        }
        if (searchResult.getMarkedCount() == 0) {
            textArea.clearMarkAllHighlights();
            findLabel.setText("0个结果");
            return;
        }
        // 向前搜搜
        boolean searchForward = searchContext.getSearchForward();
        int markedCount = searchResult.getMarkedCount();
        // 当前位置 = 搜索总数，如果向前搜索，当前位置=1。向后搜搜，当前位置--。
        if (findNextPrevIdx == markedCount) {
            if (searchForward) {
                findNextPrevIdx = 1;
            } else {
                findNextPrevIdx--;
            }
        }
        // 向后查找，findNextPrevIdx = 0
        else if (!searchForward && (findNextPrevIdx == 0 || findNextPrevIdx == 1)) {
            findNextPrevIdx = markedCount;
        }
        // 正常情况
        else {
            if (searchForward) {
                findNextPrevIdx++;
            } else {
                findNextPrevIdx--;
            }
        }
        findLabel.setText(findNextPrevIdx + "/" + searchResult.getMarkedCount());
    }


    /**
     * 更新替换组件显示隐藏
     *
     * @param showReplace 显示更换部件
     */
    private void updateReplaceComp(boolean showReplace) {
        // 替换的部分显示
        if (showReplace) {
            replaceField.setVisible(true);
            replaceButton.setVisible(true);
            replaceAllButton.setVisible(true);
        } else {
            // 隐藏替换的部分
            replaceField.setVisible(false);
            replaceButton.setVisible(false);
            replaceAllButton.setVisible(false);
        }
    }

    /**
     * 创建替换输入框
     *
     * @return {@link JTextField }
     */
    private JTextField createReplaceField() {
        JTextField replaceField = new JTextField();
        JButton searchHistoryButton = new JButton(new FlatSearchWithHistoryIcon(true));
        searchHistoryButton.setToolTipText("替换历史记录");
        searchHistoryButton.addActionListener(e -> {
            JPopupMenu popupMenu = new JPopupMenu();
            popupMenu.add("(空)");
            popupMenu.show(searchHistoryButton, 0, searchHistoryButton.getHeight());
        });
        replaceField.putClientProperty(FlatClientProperties.TEXT_FIELD_LEADING_COMPONENT, searchHistoryButton);
        replaceField.putClientProperty(FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true);
        return replaceField;
    }

    /**
     * 创建查找输入框
     *
     * @return {@link JTextField }
     */
    private JTextField createFindField() {
        JTextField findField = new JTextField();

        JButton searchHistoryButton = new JButton(new FlatSearchWithHistoryIcon(true));
        searchHistoryButton.setToolTipText("搜索历史记录");
        searchHistoryButton.addActionListener(e -> {
            JPopupMenu popupMenu = new JPopupMenu();
            popupMenu.add("(空)");
            popupMenu.show(searchHistoryButton, 0, searchHistoryButton.getHeight());
        });
        findField.putClientProperty(FlatClientProperties.TEXT_FIELD_LEADING_COMPONENT, searchHistoryButton);

        //add(compsTextField, "cell 1 15 2 1,growx");

        matchCaseButton = new JToggleButton(new FlatSVGIcon("icons/matchCase.svg"));
        matchCaseButton.setRolloverIcon(new FlatSVGIcon("icons/matchCaseHovered.svg"));
        matchCaseButton.setSelectedIcon(new FlatSVGIcon("icons/matchCaseSelected.svg"));
        matchCaseButton.setToolTipText("区分大小写");


        // whole words button
        wordsButton = new JToggleButton(new FlatSVGIcon("icons/words.svg"));
        wordsButton.setRolloverIcon(new FlatSVGIcon("icons/wordsHovered.svg"));
        wordsButton.setSelectedIcon(new FlatSVGIcon("icons/wordsSelected.svg"));
        wordsButton.setToolTipText("全词匹配");

        // regex button
        regexButton = new JToggleButton(new FlatSVGIcon("icons/regex.svg"));
        regexButton.setRolloverIcon(new FlatSVGIcon("icons/regexHovered.svg"));
        regexButton.setSelectedIcon(new FlatSVGIcon("icons/regexSelected.svg"));
        regexButton.setToolTipText("正则表达式");

        JToolBar searchToolbar = new JToolBar();
        searchToolbar.add(matchCaseButton);
        searchToolbar.add(wordsButton);
        searchToolbar.addSeparator();
        searchToolbar.add(regexButton);
        findField.putClientProperty(FlatClientProperties.TEXT_FIELD_TRAILING_COMPONENT, searchToolbar);
        findField.putClientProperty(FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true);
        return findField;
    }

    public void setShowReplace(boolean showReplace) {
        updateReplaceComp(showReplace);
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {

            BaseFrame frame = new BaseFrame();
            frame.setLayout(new BorderLayout());

            RSyntaxTextFindBar panel = new RSyntaxTextFindBar(true, null, new SearchContext());


            frame.add(panel, BorderLayout.CENTER);
            frame.setVisible(true);
        });
    }

}

